package com.crazymakercircle.dhptester.distributed;

import com.crazymakercircle.constants.ServerConstants;
import com.crazymakercircle.entity.TaskData;
import com.crazymakercircle.entity.TestResultData;
import com.crazymakercircle.util.FileHelper;
import com.crazymakercircle.zk.CuratorZKclient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import static com.crazymakercircle.constants.ServerConstants.*;

/**
 * IM 节点的ZK协调客户端
 * create by 尼恩 @ 疯狂创客圈
 **/
@Data
@Slf4j
public class TaskManger
{

    private static TaskManger INSTANCE = null;
    //Zk curator 客户端
    private CuratorFramework client = null;

    //保存当前Znode节点的路径，创建后返回
    private String pathRegistered = null;


    private boolean inited = false;


    private TaskManger()
    {

    }

    public static synchronized TaskManger getInstance()
    {
        if (null == INSTANCE)
        {
            INSTANCE = new TaskManger();
            INSTANCE.init();
        }
        return INSTANCE;
    }

    // 在zookeeper中创建临时节点
    public synchronized void init()
    {

        if (inited)
        {
            return;
        }
        inited = true;
        if (null == client)
        {
            this.client = CuratorZKclient.instance.getClient();
        }

        createParentIfNeeded(ServerConstants.TASK_PATH);
    }


    /**
     * 创建父节点
     *
     * @param managePath 父节点路径
     */
    private void createParentIfNeeded(String managePath)
    {

        try
        {
            Stat stat = client.checkExists().forPath(managePath);
            if (null == stat)
            {

                // 创建一个 ZNode 节点
                // 节点的数据为 payload
                byte[] payload = EMPTY.getBytes("UTF-8");

                client.create()
                        .creatingParentsIfNeeded()
                        .withMode(CreateMode.PERSISTENT)
                        .forPath(managePath, payload);

            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    /**
     * 上传用例
     *
     * @param path 用例的json 文件路径
     */
    public void uploadTestCase(String path)
    {

        createParentIfNeeded(ServerConstants.TASK_PATH);
        FileHelper fileHelper = new FileHelper(path);
        String content = null;
        try
        {
            content = fileHelper.getTestDataString();
            if (StringUtils.isNotBlank(content))
            {
                TaskData taskData = new TaskData();
                taskData.setJson(content);
                byte[] bytes = taskData.toJson().getBytes("UTF-8");
                CuratorZKclient.instance.updateData(ServerConstants.TASK_PATH, bytes);
            }

            log.info("test case upload succeed!");
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 查看用例
     */
    public void viewTestCase()
    {
        try
        {
            Stat stat = client.checkExists().forPath(ServerConstants.TASK_PATH);
            if (null != stat)
            {
                String json = CuratorZKclient.instance.readNode(ServerConstants.TASK_PATH);
                System.out.println(json);
                return;
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("has not upload any case!");
    }


    /**
     * 创建执行实例
     */
    public void runCase()
    {


        String managePath = ServerConstants.TASK_PATH;
        try
        {
            Stat stat = client.checkExists().forPath(managePath);
            if (null == stat)
            {
                System.out.println("please upload test case first!");
                return;
            }

            String json = CuratorZKclient.instance.readNode(managePath);
            if (null == json || EMPTY.equals(json))
            {
                System.out.println("please upload test case first!");
                return;

            }
            String taskPath = PATH_TASK_INST;
            // 创建一个 ZNode 节点
            // 节点的数据为 payload
            byte[] payload = json.getBytes("UTF-8");

            client.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.PERSISTENT_SEQUENTIAL)
                    .forPath(taskPath, payload);


        } catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    /**
     * 查看执行实例
     */
    public void viewRunResult()
    {

        String managePath = ServerConstants.TASK_PATH;
        try
        {
            Stat stat = client.checkExists().forPath(managePath);
            if (null == stat)
            {
                System.out.println("please upload test case first!");
                return;
            }

            List<String> list = CuratorZKclient.instance.readChildren(managePath);
            if (null == list || list.size() < 1)
            {
                System.out.println("please start one test first!");
                return;

            }
            for (String child : list)
            {
                String fullPath = managePath + "/" + child;

                report(fullPath);
            }
//            String taskPath = PATH_TASK_INST;
//            // 创建一个 ZNode 节点
//            // 节点的数据为 payload
//            byte[] payload =EMPTY.getBytes("UTF-8");
//
//            client.create()
//                    .creatingParentsIfNeeded()
//                    .withMode(CreateMode.PERSISTENT_SEQUENTIAL)
//                    .forPath(taskPath, payload);


        } catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    private void report(String runPath)
    {

        System.out.println("======================================= " + runPath + " ===============================================");

        List<String> list = CuratorZKclient.instance.readChildren(runPath);
        if (null == list || list.size() < 1)
        {
            return;
        }
        List<TestResultData> taskDataList = new ArrayList<>();

        for (String child : list)
        {
            String fullPath = runPath + "/" + child;
            String json = CuratorZKclient.getSingleton().readNode(fullPath);
            if (null != json)
            {
                TestResultData testResultData = TestResultData.fromJson(json);
                if (null != testResultData)
                {
                    testResultData.setPath(fullPath);
                    taskDataList.add(testResultData);
                }
            }
        }

        AtomicLong reqs = new AtomicLong();
        AtomicLong time = new AtomicLong();

        if (taskDataList.size() > 0)
        {
            taskDataList.stream().forEach(testResultData ->
            {
                System.out.println("testResultData.getPath() = " + testResultData.getPath());
                testResultData.report();
                reqs.addAndGet(testResultData.getTotal_req());
                if(testResultData.getTakeTime()>time.get())
                time.set(testResultData.getTakeTime());

            });

        }
        String qps = DF.format((reqs.get() / time.get()));
        System.out.println("total qps = " + qps);
        System.out.println("total qps = " + qps);

    }

    /**
     * 删除执行结果
     */
    public void clearTestResult()
    {
        String managePath = ServerConstants.TASK_PATH;
        try
        {
            Stat stat = client.checkExists().forPath(managePath);
            if (null == stat)
            {
                return;
            }

            List<String> list = CuratorZKclient.instance.readChildren(managePath);
            if (null == list || list.size() < 1)
            {
                return;

            }
            for (String child : list)
            {
                String fullPath = managePath + "/" + child;
                CuratorZKclient.getSingleton().deleteChild(fullPath);
                CuratorZKclient.getSingleton().deleteNode(fullPath);
            }

        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

